package org.fhm.zdte.protocol.zrudp.service;

import org.fhm.substrate.annotation.Component;
import org.fhm.substrate.annotation.Setup;
import org.fhm.substrate.service.LoggerHandler;
import org.fhm.substrate.standard.ILogger;
import org.fhm.zdte.common.protocol.AbstractMessageParser;
import org.fhm.zdte.common.protocol.AbstractMessageStandard;
import org.fhm.zdte.protocol.zrudp.constant.DatagramHead;
import org.fhm.zdte.protocol.zrudp.pojo.ZRUDPMessageStandard;
import org.fhm.zdte.protocol.zrudp.standard.IDataConvertor;
import org.fhm.zdte.protocol.zrudp.standard.IProtocolMessageConvertor;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * The ZRUDP that is Packet-Parser.
 *
 * @author 谭波
 * @since 2023/10/31
 */
@Component("zrudp")
public class ZRUDPMessageParser extends AbstractMessageParser {

    private final ILogger logger = LoggerHandler.getLogger(ZRUDPMessageParser.class);

    @Setup
    private IProtocolMessageConvertor protocolMessageConverter;

    @Setup
    private IDataConvertor<DatagramHead> dataConvertor;

    @Override
    public byte[] encoding(AbstractMessageStandard messageStandard) {
        ZRUDPMessageStandard message = (ZRUDPMessageStandard) messageStandard;
        if (Objects.isNull(message)) {
            return new byte[0];
        }
        return dataConvertor
                .ofPipeline(DatagramHead::values)
                .joinFor(
                        (h, stream) -> protocolMessageConverter
                                .ofMessageMemberToByteArray()
                                .prepare(h)
                                .obtainMember(message)
                                .convert()
                                .addHeadSeparator(stream))
                .generation();
    }


    @Override
    public AbstractMessageStandard decoding(byte[] buffer) {
        ZRUDPMessageStandard message = new ZRUDPMessageStandard();
        if (Objects.isNull(buffer) || buffer.length == 0) {
            return message;
        }
        dataConvertor
                .ofConvertor(DatagramHead::values)
                .prepare(() -> {
                    List<List<Byte>> headList = new ArrayList<>();
                    try {
                        List<Byte> bytes = new ArrayList<>();
                        int length = buffer.length;
                        for (int i = 0, len = (length - 2); i < len; i++) {
                            if (protocolMessageConverter.getHeadSeparatorMatcher().apply(buffer, i)) {
                                if (bytes.size() > 1)
                                    headList.add(bytes);
                                bytes = new ArrayList<>();
                                i += 3;
                            }
                            if (i >= length) {
                                continue;
                            }
                            bytes.add(buffer[i]);
                        }
                    } catch (Exception e) {
                        logger.error("an error is reported during the preparation phase of converting byte arrays to messages", e);
                    }
                    return headList;
                }, message)
                .setMatchFunction((h, b) -> b.equals(h.getValueBit()))
                .makeFor(
                        (head, m, headValue) -> protocolMessageConverter
                                .ofByteArrayToMessage()
                                .prepare(m)
                                .preAssemble(head.getFieldName(), headValue)
                                .afterAssemble()
                );
        return message;
    }

}
